import { h, Ref, VNode } from 'vue';
import {
  ElFormItem,
  ElForm, ElRow, ElCol, FormRules
} from 'element-plus';

/**
 * 通用表单formItem配置接口
 */
export interface BaseFormItemConfigInterface<T> {
  prop: keyof T;
  key?: string;
  label?: string;
  labelWidth?: string;
  inputWidth?: string;
  disabled?: boolean | ((formData: T) => boolean);
  rulePropName?: string;
  colSpan?: number;
  onChange?: (val: any, formData: T) => any;
  onClick?: (formData: T) => any;
  onBlur?: (formData: T) => any;
  hidden?: boolean | ((formData: T) => boolean);
  createMethod(config: this, formData: T): VNode;
  [k: string]: any;
}

/**
 * 通用表单配置接口实现类(目前没有extends的原因是createMethod的多态有问题)
 */
export abstract class BaseFormItemConfig<T> {
  public prop: keyof T;
  public key?: string;
  public label?: string;
  public labelWidth?: string;
  public inputWidth?: string;
  public disabled?: boolean | ((formData: T) => boolean);
  public rulePropName?: string;
  public colSpan?: number;
  public hidden?: boolean | ((formData: T) => boolean);
  public onChange?: (val: any, formData: T) => any;
  public onClick?: (formData: T) => any;
  public onBlur?: (formData: T) => any;

  public abstract createMethod(config: this, formData: T): VNode;

  protected constructor (data: Omit<BaseFormItemConfigInterface<T>, 'createMethod'>) {
    this.prop = data.prop;
    this.key = data.key;
    this.label = data.label;
    this.labelWidth = data.labelWidth;
    this.inputWidth = data.inputWidth ?? '100%';
    this.disabled = data.disabled;
    this.colSpan = data.colSpan;
    this.rulePropName = data.rulePropName;
    this.hidden = data.hidden ?? false;
    this.onChange = data.onChange;
    this.onClick = data.onClick;
    this.onBlur = data.onBlur;
    console.log(this.inputWidth);
  }
}

/**
 * 表单设置接口
 */
export interface FormConfig<T> {
  bindData: T;
  ref?: Ref<InstanceType<typeof ElForm> | null>;
  rules?: FormRules;
  labelWidth?: number | string;
  formItemType?: 'normal' | 'row';
  labelPosition?: 'left' | 'right' | 'top';
  itemsConfig: BaseFormItemConfigInterface<T>[];
}

/**
 * 动态表单单个formItem生成
 * @param config 生成配置项
 * @param formData 绑定的表单对象
 */
export const createFormItemFromConfig: <T>(config: BaseFormItemConfig<T>, formData: T) => VNode = (config, formData): VNode => {
  return (typeof config.hidden === 'function' && config.hidden(formData)) || config.hidden === true
    ? <ElCol span={0}></ElCol>
    : <ElCol span={config.colSpan || 24}>
      <ElFormItem labelWidth={!config.label ? '0' : ''} label={config?.label} prop={config.rulePropName ? config.rulePropName : config.prop as string} key={`formItemKey${config.key ?? config.prop as string}`}>
        {config.createMethod(config, formData)}
      </ElFormItem>
    </ElCol>;
};

/**
 * 动态表单批量formItem生成
 * @param config 生成配置项(复数项)
 * @param formData 绑定的表单对象
 */
export const createFormItemsFromConfig: <T>(config: (BaseFormItemConfig<T>)[], formData: T,) => VNode[] = (config, formData): VNode[] => {
  return config.map(item => createFormItemFromConfig(item, formData));
};

/**
 * 根据配置项动态生成form表单
 * @param formConfig 绑定的表单属性(包含绑定的配置属性)
 */
export const createDefaultFormFromConfig: <T>(formConfig: FormConfig<T>) => VNode = (formConfig) => {
  return <ElForm ref={formConfig.ref} rules={formConfig.rules} model={formConfig.bindData}
                 labelWidth={formConfig.labelWidth || '120px'} labelPosition={formConfig.labelPosition || 'left'}>
    <ElRow>
      {createFormItemsFromConfig(formConfig.itemsConfig, formConfig.bindData)}
    </ElRow>
  </ElForm>;
};
